package com.yanqu.road.server.gameplayer.module.activity.pasture;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.ValueParamArgs;
import com.yanqu.road.entity.activity.pasture.*;
import com.yanqu.road.entity.activity.pasture.config.PastureAnimalConfig;
import com.yanqu.road.entity.activity.pasture.config.PastureModuleConfig;
import com.yanqu.road.entity.activity.pasture.config.PasturePracticeConfig;
import com.yanqu.road.entity.activity.pasture.config.PastureSkillConfig;
import com.yanqu.road.entity.activity.pasture.extra.PastureChickenExtraData;
import com.yanqu.road.entity.activity.pasture.extra.PasturePigExtraData;
import com.yanqu.road.entity.activity.pasture.extra.PastureSnakeExtraData;
import com.yanqu.road.entity.config.goods.MallInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.LogPastureGame;
import com.yanqu.road.entity.log.LogPastureOperate;
import com.yanqu.road.logic.bussiness.activity.PastureBussiness;
import com.yanqu.road.pb.activity.PastureProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.pasture.PastureMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.pb.PasturePb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.CrossProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.LocalDateTimeHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.IntStream;

/**
 * 牧场点兵
 */
public class PastureModule extends GeneralModule {

    public PastureUserData userData;

    public PastureModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        PastureConfig config = PastureMgr.getConfig();
        if (config != null && ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            userData = PastureBussiness.getPastureUserData(config.getActivityInfo().getActivityId(), player.getUserId());
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return false;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                PastureBussiness.addPastureUserData(userData);
            } else if (userData.isUpdateOption()) {
                PastureBussiness.updatePastureUserData(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        if (SystemOpenMgr.systemOpen(player, eSystemId.Pasture.getValue())) {
            initSystem();
        }
    }

    public void initSystem() {
        syncConfig();
        initUserData();
        syncUserData();
    }

    /**
     * 初始化玩家数据
     */
    public synchronized void initUserData() {

        // 没有活动
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        ActivityInfo activityInfo = config.getActivityInfo();

        // 已经有数据了
        if (userData != null && userData.getActivityId() == activityInfo.getActivityId()) {
            return;
        }

        PastureUserData tmpUserData = new PastureUserData();
        tmpUserData.setActivityId(activityInfo.getActivityId());
        tmpUserData.setUserId(getUserId());
        tmpUserData.setMaxScore(-1);
        tmpUserData.setLastMaxScore(-1);
        tmpUserData.setTodayTimes(0);
        tmpUserData.setAnimalDataMap(new HashMap<>());
        tmpUserData.setGameData(new PastureGameData());
        tmpUserData.setPracticeData(new PastureGameData());
        tmpUserData.setBuySilverToken(false);
        tmpUserData.setBuyGoldToken(false);
        tmpUserData.setResetTime(LocalDateTimeHelper.getZeroTimeTimeStamp());
        tmpUserData.setRecentStepsGameData(new LinkedList<>());
        tmpUserData.setRecentStepsPracticeData(new LinkedList<>());
        tmpUserData.setUpdateTime(System.currentTimeMillis());
        tmpUserData.setInsertOption();
        userData = tmpUserData;
    }


    /**
     * 同步配置
     */
    public void syncConfig() {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        // 同步配置数据
        player.sendPacket(ClientProtocol.U_PASTURE_CONFIG_SYNC, PasturePb.parseSyncConfigTemp(config, player.getLanguage()));

    }

    /**
     * 同步玩家数据
     */
    public void syncUserData() {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        if (userData == null) {
            return;
        }

        //热更修复代码
        try {
            if (userData != null) {
                PastureGameData gameData = getGameData(false);
                if (gameData != null && gameData.getGameStatus() == ePastureGameStatusType.WaitPassed.getValue()) {
                    gamePass(false);
                }
            }
        } catch (Exception e) {
            log.error("热更代码错误:" + e);
        }

        PastureProto.SyncPastureDataMsg.Builder builder = PastureProto.SyncPastureDataMsg.newBuilder();
        builder.setUserData(PasturePb.parseUserDataTemp(userData));
        // 同步用户数据
        player.sendPacket(ClientProtocol.U_PASTURE_DATA_SYNC, builder);
    }

    public void rechargeToken(int activityId, MallInfo mallInfo) {
        if (userData.getActivityId() != activityId) {
            return;
        }
        if (mallInfo.getShopType() == eShopType.ChineseChessSilverToken.getValue()) {
            player.notifyListener(eGamePlayerEventType.PastureSilverToken.getValue(), userData.getMaxScore());
            userData.setBuySilverToken(true);
        }
        if (mallInfo.getShopType() == eShopType.ChineseChessGoldToken.getValue()) {
            player.notifyListener(eGamePlayerEventType.PastureGoldToken.getValue(), userData.getMaxScore());
            userData.setBuyGoldToken(true);
        }
        // 同步用户数据
        syncUserData();
    }

    public boolean isBuyToken(MallInfo mallInfo) {
        if (userData == null) {
            return true;
        }
        if (mallInfo.getShopType() == eShopType.ChineseChessSilverToken.getValue()) {
            return userData.isBuySilverToken();
        }
        if (mallInfo.getShopType() == eShopType.ChineseChessGoldToken.getValue()) {
            return userData.isBuyGoldToken();
        }
        return false;
    }

    /**
     * 购买后设置可以复活
     */
    public void canRevive() {
        if (userData == null) {
            return;
        }
        userData.setCanRevive(true);
        syncUserData();
    }


    /**
     * 操作前校验数据、活动是否有效
     *
     * @param isPractice
     */
    public boolean preCheck(boolean isPractice) {
        // 检测活动是否有效
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return false;
        }
        if (isPractice) {
            // 练习模式展示期都可操作
            if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
                return false;
            }
        } else {
            if (!ActivityMgr.activityInTime(config.getActivityInfo())) {
                return false;
            }
        }
        if (userData == null) {
            return false;
        }
        return true;
    }

    //============================================CMD=====================================================

    /**
     * 开始游戏
     *
     * @param isPractice 是否练习模式
     */
    public int startGame(boolean isPractice) {
        if (!preCheck(isPractice)) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        PastureProto.PastureStartGameRespMsg.Builder respMsg = PastureProto.PastureStartGameRespMsg.newBuilder();
        PastureConfig config = PastureMgr.getConfig();
        // 获取游戏数据
        PastureGameData gameData = getGameData(isPractice);
        // 如果当前在游戏中，则不能开始新的游戏(练习模式除外)
        if (!isPractice && gameData.getGameStatus() == ePastureGameStatusType.Running.getValue()) {
            // 返回当前游戏数据
            respMsg.setRet(GameErrorCode.E_PASTURE_GAMEING);
            respMsg.setGameData(PasturePb.parseGameDataTemp(gameData));
            player.sendPacket(Protocol.U_PASTURE_START_GAME, respMsg);
            return 0;
        }
        // 判断次数是否足够
        if (!isPractice && userData.getTodayTimes() >= config.getPastureEnergy()) {
            // 判断道具是否足够
            String consumeProperty = PropertyHelper.parseGoodsToString(config.getPastureEnergyItemId(), BigInteger.valueOf(config.getPastureEnergyCost()));
            Property consume = PropertyHelper.parseStringToProperty(consumeProperty);
            if (!player.getModule(CurrencyModule.class).removeCurrency(consume, eLogMoneyType.Pasture, eLogMoneyType.PastureStartGameConsume)) {
                return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
            }
        }
        if (!isPractice) {
            // 扣除次数
            userData.setTodayTimes(userData.getTodayTimes() + 1);
            userData.setGameCnt(userData.getGameCnt() + 1);
        }
        // 生成新的游戏数据
        gameData = initGameData(isPractice);
        afterOperateHandler(isPractice, gameData, false, false);
        // 同步玩家数据
        syncUserData();

        respMsg.setRet(0);
        respMsg.setGameData(PasturePb.parseGameDataTemp(gameData));
        respMsg.setMoveResultMsg(PasturePb.parseMoveData(gameData));
        player.sendPacket(Protocol.U_PASTURE_START_GAME, respMsg);
        return 0;
    }

    /**
     * 移动
     *
     * @param isPractice 是否练习模式
     * @param y          纵坐标
     * @param x1         原横坐标
     * @param x2         目标横坐标
     */
    public int moveBlock(boolean isPractice, int y, int x1, int x2) {
        if (!preCheck(isPractice)) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        // 获取游戏数据
        PastureGameData gameData = getGameData(isPractice);
        if (gameData == null) {
            return GameErrorCode.E_PASTURE_NO_GAME_DATA;
        }
        PastureProto.PastureMoveBlockRespMsg.Builder respMsg = PastureProto.PastureMoveBlockRespMsg.newBuilder();
        // 检测有没有进行中的游戏
        if (!isGameRunning(gameData)) {
            respMsg.setRet(GameErrorCode.E_PASTURE_NO_GAME_DATA);
            respMsg.setGameData(PasturePb.parseGameDataTemp(gameData));
            player.sendPacket(Protocol.U_PASTURE_MOVE_BLOCK, respMsg);
            return 0;
        }
        // 计算位移
        int offset = x2 - x1;
        if (offset == 0) {
            return GameErrorCode.E_PASTURE_DONT_MOVE;
        }
        // 获取当前位置(x1,y)的格子对象
        PastureBlockData blockData = getBlockData(gameData, x1, y);
        if (blockData == null) {
            return GameErrorCode.E_PASTURE_DONT_MOVE;
        }

        if (offset > 0) {
            // 向右移动,判断当前对象右边是否都为空格子
            if (!isAllSpaceInRange(gameData, y, blockData.getRight() + 1, blockData.getRight() + offset)) {
                // 阻挡
                return GameErrorCode.E_PASTURE_DONT_MOVE;
            }
        } else {
            // 向左移动,判断当前对象左边是否都为空格子
            if (!isAllSpaceInRange(gameData, y, blockData.getLeft() + offset, blockData.getLeft() - 1)) {
                // 阻挡
                return GameErrorCode.E_PASTURE_DONT_MOVE;
            }
        }
        // 操作前处理
        beforeOperateHandle(isPractice, gameData, false, false);
        // 记录移动过程
        PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
        moveResult.setOriginBlockData(blockData.clone());
        // 向左移动offset个格子
        blockDataChange(blockData, blockData.getY(), blockData.getLeft() + offset, blockData.getRight() + offset);
        moveResult.setTargetBlockData(blockData.clone());
        moveResult.setMoveType(ePastureGameMoveType.Default.getValue());
        addMoveData(gameData, moveResult);
        // 操作后处理
        afterOperateHandler(isPractice, gameData, false, false);
        respMsg.setRet(0);
        respMsg.setGameData(PasturePb.parseGameDataTemp(gameData));
        respMsg.setMoveResultMsg(PasturePb.parseMoveData(gameData));
        player.sendPacket(Protocol.U_PASTURE_MOVE_BLOCK, respMsg);
        return 0;
    }


    /**
     * 使用技能
     */
    public int useSkill(boolean isPractice, int animalId) {
        if (!preCheck(isPractice)) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        PastureGameData gameData = getGameData(isPractice);
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 判断能量是否足够
        int needCostEnergy = config.getPastureSkillEnergyMax().get(Math.min(gameData.getUseSkillCnt(), config.getPastureSkillEnergyMax().size() - 1));
        if (gameData.getEnergy() < needCostEnergy) {
            return GameErrorCode.E_PASTURE_ENERGY_NOT_ENOUGH;
        }
        // 获取技能id
        Map<Integer, PastureAnimalConfig> animalConfigMap = config.getAnimalConfigMap();
        if (animalConfigMap == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        PastureAnimalConfig animalConfig = animalConfigMap.get(animalId);
        if (animalConfig == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 是否可以激活技能
        if (animalConfig.getBurst() == 0) {
            return GameErrorCode.E_PASTURE_DONT_USE_SKILL;
        }
        int skillId = animalConfig.getSkillId();
        PastureSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        ePastureSkillType skillType = ePastureSkillType.forValue(skillId);
        if (skillType == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 是否能重复触发
        boolean isRepeat = skillConfig.getRepeat() == 1;
        // 操作前处理
        beforeOperateHandle(isPractice, gameData, true, false);
        // 扣除能量
        gameData.setEnergy(gameData.getEnergy() - needCostEnergy);
        gameData.setUseSkillCnt(gameData.getUseSkillCnt() + 1);
        gameData.setTotalCostEnergy(gameData.getTotalCostEnergy() + needCostEnergy);
        if (!isPractice) {
            addUseSkillRecord(gameData, animalId);
        }
        switch (skillType) {
            case Chicken:
                skillOfChicken(gameData, animalId, isRepeat);
                break;
            case Cat:
                skillOfCat(gameData, animalId, isRepeat);
                break;
            case Weasel:
                skillOfWeasel(gameData, animalId, isRepeat);
                break;
            case Donkey:
                skillOfDonkey(gameData, animalId, isRepeat);
                break;
            case Fox:
                skillOfFox(gameData, animalId, isRepeat);
                break;
            case Snake:
                skillOfSnake(gameData, animalId, isRepeat);
                break;
            case Pig:
                skillOfPig(gameData, animalId, isRepeat);
                break;
            case Bear:
                skillOfBear(gameData, animalId, isRepeat);
                break;
            default:
                break;
        }
        // 操作后处理
        afterOperateHandler(isPractice, gameData, true, false);
        int useSkillCnt = 0;
        if (!isPractice) {
            Map<Integer, PastureAnimalData> animalDataMap = userData.getAnimalDataMap();
            PastureAnimalData pastureAnimalData = animalDataMap.getOrDefault(animalId, new PastureAnimalData());
            useSkillCnt = pastureAnimalData.getUseSkillCnt() + 1;
            // 记录活动动物激活次数
            pastureAnimalData.setUseSkillCnt(useSkillCnt);
            animalDataMap.put(animalId, pastureAnimalData);
            userData.setAnimalDataMap(animalDataMap);
            // 激活
            player.notifyListener(eGamePlayerEventType.PastureActivateAnimals.getValue(), animalId);
        }
        PastureProto.PastureUseSkillRespMsg.Builder respMsg = PastureProto.PastureUseSkillRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(PasturePb.parseGameDataTemp(gameData));
        respMsg.setMoveResultMsg(PasturePb.parseMoveData(gameData));
        respMsg.setUseSkillCnt(useSkillCnt);
        player.sendPacket(Protocol.U_PASTURE_USE_SKILL, respMsg);
        return 0;
    }

    /**
     * 添加
     */
    private void addUseSkillRecord(PastureGameData gameData, int animalId) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return;
        }
        Map<Integer, PastureAnimalConfig> animalConfigMap = config.getAnimalConfigMap();
        if (animalConfigMap == null) {
            return;
        }
        PastureAnimalConfig animalConfig = animalConfigMap.get(animalId);
        if (animalConfig == null) {
            return;
        }
        int skillId = animalConfig.getSkillId();
        // 激活的动物id
        gameData.setUseSkillAnimalId(animalId);
        // 记录使用技能
        gameData.getUseSkillTotalMap().put(skillId, gameData.getUseSkillTotalMap().getOrDefault(skillId, 0) + 1);
    }

    /**
     * 使用充能道具
     */
    public int useSkillItem(int count) {
        if (!preCheck(false)) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        // 只能在游戏模式使用
        PastureGameData gameData = getGameData(false);
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 判断是否达到上限
        if (gameData.getUseSkillItemCnt() >= config.getPastureSkillItemLimit()) {
            return GameErrorCode.E_PASTURE_USE_SKILL_ITEM_LIMIT;
        }
        // 判断道具是否足够
        String consumeProperty = PropertyHelper.parseGoodsToString(config.getPastureSkillItemId(), BigInteger.valueOf(count));
        Property consume = PropertyHelper.parseStringToProperty(consumeProperty);
        if (!player.getModule(CurrencyModule.class).removeCurrency(consume, eLogMoneyType.Pasture, eLogMoneyType.PastureSkillItemConsume)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        // 增加能量
        // 充能数值=当前使用技能消耗能量*参数（千分比）
        long addEnergy = ((Double) (PastureMgr.getSkillEnergyMax(gameData.getUseSkillCnt()) * (config.getPastureSkillItemNum() / 1000.0))).longValue();
        gameData.setEnergy(gameData.getEnergy() + addEnergy * count);
        gameData.setUseSkillItemCnt(gameData.getUseSkillItemCnt() + count);
        PastureProto.PastureUseSkillItemRespMsg.Builder respMsg = PastureProto.PastureUseSkillItemRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setEnergy(gameData.getEnergy());
        respMsg.setUseSkillItemCnt(gameData.getUseSkillItemCnt());
        player.sendPacket(Protocol.U_PASTURE_USE_SKILL_ITEM, respMsg);
        return 0;
    }


    /**
     * 重置回上一步的游戏数据(复活)
     */
    public int reserveGameData(boolean isPractice, boolean testMode) {
        if (!preCheck(isPractice)) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        LinkedList<PastureGameData> recentStepsData;
        if (isPractice) {
            recentStepsData = userData.getRecentStepsPracticeData();
        } else {
            recentStepsData = userData.getRecentStepsGameData();
        }
        if (recentStepsData.size() == 0) {
            return GameErrorCode.E_PASTURE_NO_GAME_DATA;
        }
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        PastureGameData originGameData = getGameData(isPractice).clone();
        // 只有等待复活状态才可使用
        if (!testMode && originGameData.getGameStatus() != ePastureGameStatusType.Revive.getValue()) {
            return GameErrorCode.E_PASTURE_DONT_RESERVE_DATA;
        }
        // 部分数据需要保留、返回上一步的次数
        PastureGameData gameData = recentStepsData.getLast();
        PastureGameData lastGameDataClone = gameData.clone();
        // 判断有无免费次数
        if (!testMode) {
            if (!userData.isCanRevive() || originGameData.getFreeRestartCnt() >= config.getPastureRestartTime().get(1)) {
                if (originGameData.getRestartCnt() >= config.getPastureRestartTime().get(0)) {
                    return GameErrorCode.E_PASTURE_RESTART_TIME_LIMIT;
                }
                // 消耗元宝
                if (!player.getModule(CurrencyModule.class).removeCurrency(new Property(PropertyHelper.parseStringToProperty(config.getPastureRestartCost())), eLogMoneyType.Pasture, eLogMoneyType.PastureReserveGameDataConsume)) {
                    return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
                }
                gameData.setRestartCnt(originGameData.getRestartCnt() + 1);
            } else {
                gameData.setFreeRestartCnt(originGameData.getFreeRestartCnt() + 1);
            }
        }
        beforeOperateHandle(isPractice, gameData, false, true);
        // 移除记录
        recentStepsData.removeLast();
        if (!testMode) {
            // 消除底下2行数据
            clearRow(gameData, PastureMgr.MAX_HEIGHT - 2, PastureMgr.MAX_HEIGHT - 1, true);
        }
        afterOperateHandler(isPractice, gameData, false, true);
        if (isPractice) {
            userData.setRecentStepsPracticeData(recentStepsData);
        } else {
            userData.setRecentStepsGameData(recentStepsData);
        }
        PastureProto.PastureReserveGameDataRespMsg.Builder respMsg = PastureProto.PastureReserveGameDataRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(PasturePb.parseGameDataTemp(gameData));
        respMsg.setMoveResultMsg(PasturePb.parseMoveData(gameData));
        // 需要返回一步的结果数据
        respMsg.setOriginGameData(PasturePb.parseGameDataTemp(lastGameDataClone));
        player.sendPacket(Protocol.U_PASTURE_RESERVE_GAME_DATA, respMsg);
        return 0;
    }


    /**
     * 动物晋升
     */
    public int animalPromote(int animalId) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || config.getAnimalConfigMap() == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        if (userData == null) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
        if (animalConfig == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 判断是否在动物名录中
        if (animalConfig.getDisplay() == 0) {
            return GameErrorCode.E_PASTURE_ANIMAL_DONT_PROMOTE;
        }
        // 获取当前等级
        Map<Integer, PastureAnimalData> animalDataMap = userData.getAnimalDataMap();
        PastureAnimalData animalData = animalDataMap.getOrDefault(animalId, new PastureAnimalData());
        if (animalData.getPromoteCnt() >= animalConfig.getCost().size() || animalData.getPromoteCnt() >= animalConfig.getPoint().size() - 1) {
            // 已经满级
            return GameErrorCode.E_PASTURE_ANIMAL_PROMOTE_LIMIT;
        }
        // 获取消耗
        int costNum = animalConfig.getCost().get(animalData.getPromoteCnt());
        // 消耗道具
        if (!player.getModule(CurrencyModule.class).removeCurrency(new Property(config.getPastureUpgradeItemId(), BigInteger.valueOf(costNum)), eLogMoneyType.Pasture, eLogMoneyType.PastureAnimalPromoteConsume)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        // 升级
        animalData.setAnimalId(animalId);
        animalData.setPromoteCnt(animalData.getPromoteCnt() + 1);
        animalDataMap.put(animalId, animalData);
        userData.setAnimalDataMap(animalDataMap);
        PastureProto.PastureAnimalPromoteRespMsg.Builder respMsg = PastureProto.PastureAnimalPromoteRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setAnimalData(PasturePb.parseAnimalDataTemp(animalData));
        player.sendPacket(Protocol.U_PASTURE_ANIMAL_PROMOTE, respMsg);

        // 更新游戏模式和练习模式的游戏数据（基础分增加）
        animalPromoteUpdateBaseScore(animalId);
        return 0;
    }

    /**
     * 游戏通关
     */
    public int gamePass(boolean isPractice) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 展示期都可操作
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        if (userData == null) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        // 获取游戏数据
        PastureGameData gameData = getGameData(isPractice);
        if (gameData == null) {
            return GameErrorCode.E_PASTURE_NO_GAME_DATA;
        }
        // 判断游戏是否等待通关状态
        if (gameData.getGameStatus() != ePastureGameStatusType.WaitPassed.getValue()) {
            return GameErrorCode.E_PASTURE_GAME_NO_PASSED;
        }
        // 操作前处理
        beforeOperateHandle(isPractice, gameData, false, false);
        gamePassedHandler(gameData);
        // 操作后处理
        afterOperateHandler(isPractice, gameData, false, false);
        PastureProto.PastureGamePassRespMsg.Builder respMsg = PastureProto.PastureGamePassRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(PasturePb.parseGameDataTemp(gameData));
        respMsg.setMoveResultMsg(PasturePb.parseMoveData(gameData));
        player.sendPacket(Protocol.U_PASTURE_GAME_PASS, respMsg);
        return 0;
    }

    /**
     * 完成引导
     */
    public int finishGuide(boolean finishGuide) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 展示期都可操作
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        if (userData == null) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        userData.setFinishGuide(finishGuide);
        PastureProto.PastureFinishGuideRespMsg.Builder respMsg = PastureProto.PastureFinishGuideRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setFinishGuild(userData.isFinishGuide());
        player.sendPacket(Protocol.U_PASTURE_FINISH_GUIDE, respMsg);
        return 0;
    }

    public int gameOver(boolean isPractice) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_PASTURE_CONFIG_NOT_FOUNT;
        }
        // 展示期都可操作
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        if (userData == null) {
            return GameErrorCode.E_PASTURE_ACTIVITY_NO_OPEN;
        }
        // 更新游戏状态
        PastureGameData gameData = getGameData(isPractice);
        if (gameData.getGameStatus() == ePastureGameStatusType.Finished.getValue()) {
            return GameErrorCode.E_PASTURE_HAS_BEEN_SETTLED;
        }
        gameData.setGameStatus(ePastureGameStatusType.Finished.getValue());
        // 获取当前积分的档次
        int idx = 0;
        for (int i = 0; i < config.getPastureAssessLevel().size(); i++) {
            if (gameData.getScore() >= config.getPastureAssessLevel().get(i)) {
                idx = i;
            }
        }
        // 获取奖励
        String reward = config.getPastureAssessReward().get(Math.min(idx, config.getPastureAssessReward().size() - 1));
        // 获得奖励
        player.getModule(CurrencyModule.class).addCurrency(PropertyHelper.parseStringToProperty(reward),
                eLogMoneyType.Pasture, eLogMoneyType.PastureGameOverReward);
        gameData.setReward(reward);
        if (!isPractice) {
            userData.setMaxRound(Math.max(userData.getMaxRound(), gameData.getRound()));
            userData.setLastMaxScore(userData.getMaxScore());
        }
        updateGameData(isPractice, gameData);
        // 游戏结束到跨服拿数据
        PastureProto.CrossPastureGetRankReqMsg.Builder msg = PastureProto.CrossPastureGetRankReqMsg.newBuilder();
        msg.setActivityId(config.getActivityInfo().getActivityId());
        msg.setConditionType(eGamePlayerEventType.PastureMaxScoreRank.getValue());
        msg.setScore(userData.getMaxScore());
        msg.setIsPractice(isPractice);
        player.sendPacket(CrossProtocol.C2_PASTURE_ACTIVITY_GAME_OVER, msg);
        syncUserData();
        if (!isPractice) {
            // 日志
            AutoLogMgr.add(new LogPastureGame(
                    player.getUserId(),
                    config.getActivityInfo().getActivityId(),
                    gameData.getRound(),
                    gameData.getScore(),
                    gameData.getTotalGetEnergy(),
                    gameData.getTotalCostEnergy(),
                    gameData.getUseSkillCnt(),
                    JSON.toJSONString(gameData.getUseSkillTotalMap()),
                    JSON.toJSONString(gameData.getClearBlockTotalMap()),
                    gameData.getRestartCnt() + gameData.getFreeRestartCnt(),
                    new Date()
            ));
        }
        return 0;
    }

    public void gameOverHandler(boolean isPractice, int rank) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null) {
            return;
        }
        // 展示期都可操作
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        if (userData == null) {
            return;
        }
        PastureGameData gameData = getGameData(isPractice);
        PastureProto.PastureGameOverRespMsg.Builder msg = PastureProto.PastureGameOverRespMsg.newBuilder();
        msg.setRet(0);
        msg.setRank(rank);
        msg.setReward(gameData.getReward());
        msg.setGameData(PasturePb.parseGameDataTemp(gameData));
        player.sendPacket(Protocol.U_PASTURE_GAME_OVER, msg);
    }


    //============================================CMD=====================================================


    /**
     * 初始化生成游戏数据
     *
     * @param isPractice
     */
    private PastureGameData initGameData(boolean isPractice) {
        PastureGameData gameData = new PastureGameData();
        // 初始化生成8X10的游戏数据
        for (int i = 0; i < PastureMgr.MAX_HEIGHT; i++) {
            addLastRowData(gameData, new ArrayList<>());
        }
        if (isPractice) {
            // 练习模式初始能量=首次激活消耗能量
            gameData.setEnergy(PastureMgr.getSkillEnergyMax(gameData.getUseSkillCnt()));
        } else {
            // 技能槽初始能量
            if (userData.isBuySilverToken()) {
                gameData.setEnergy(PastureMgr.getConfig().getPastureSkillEnergyStart().get(1));
            } else {
                gameData.setEnergy(PastureMgr.getConfig().getPastureSkillEnergyStart().get(0));
            }
        }
        // 清除记录
        if (isPractice) {
            userData.getRecentStepsPracticeData().clear();
        } else {
            userData.getRecentStepsGameData().clear();
        }
        // 设置为游戏中的状态
        gameData.setGameStatus(ePastureGameStatusType.Running.getValue());
        // 初始回合
        gameData.setRound(1);
        // 初始化生成的行数
        gameData.setGenerateRow(PastureMgr.INIT_GENERATE_ROW);
        if (isPractice) {
            // 练习模式提前生成残局
            genPracticeBlockData(gameData);
            gameData.setGenerateRow(0);
        }
        genBlockData(isPractice, gameData);
        return gameData;
    }

    /**
     * 生成残局
     */
    private void genPracticeBlockData(PastureGameData gameData) {
        PastureConfig config = PastureMgr.getConfig();
        Map<Integer, Map<Integer, PasturePracticeConfig>> practiceConfig = config.getPracticeConfig();
        List<Integer> allModelId = new ArrayList<>(practiceConfig.keySet());
        if (allModelId.size() == 0) {
            return;
        }
        int modelId = allModelId.get(userData.getPracticeModelIdx());
        // 模板索引增加
        userData.setPracticeModelIdx((userData.getPracticeModelIdx() + 1) % allModelId.size());
        // 残局配置
        Map<Integer, PasturePracticeConfig> lineConfigMap = practiceConfig.get(modelId);
        // 塞数据
        for (PasturePracticeConfig conf : lineConfigMap.values()) {
            List<PastureBlockData> blockDataList = new ArrayList<>();
            // 获取组合
            List<String> tempList = StringUtils.stringToStringList(conf.getBox(), "\\|");
            int x = 0;
            for (String data : tempList) {
                int animalId = Integer.parseInt(data.split("=")[0]);
                int size = Integer.parseInt(data.split("=")[1]);
                // 空格类型不生成对象
                if (animalId == 0) {
                    x += size;
                    continue;
                }
                PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
                PastureBlockData blockData = new PastureBlockData();
                blockData.setAnimalId(animalId);
                blockData.setLength(size);
                blockData.setLeft(x);
                x += blockData.getLength();
                blockData.setRight(x - 1);
                // 计算纵坐标
                blockData.setY(PastureMgr.MAX_HEIGHT);
                // 获取基础得分
                blockData.setScore(animalConfig.getPoint().get(0));
                blockData.setEnergy(animalConfig.getEnergy());
                // 添加动物朝向(默认向左)
                blockData.setDirection(-1);
                if (animalId == ePastureAnimalType.Cow.getValue()) {
                    Random random = new Random();
                    blockData.setDirection(random.nextBoolean() ? 1 : -1);
                }
                blockDataList.add(blockData);
            }
            if (conf.getStart() == 1) {
                gameData.getInitBlockDataList().add(blockDataList);
            } else {
                gameData.getBeforeGenBlockDataList().add(blockDataList);
            }
        }
    }

    /**
     * 获取游戏数据
     *
     * @param isPractice 是否练习模式
     */
    private PastureGameData getGameData(boolean isPractice) {
        return isPractice ? userData.getPracticeData() : userData.getGameData();
    }

    /**
     * 更新游戏数据
     *
     * @param isPractice 是否练习模式
     * @param gameData   游戏数据
     */
    private void updateGameData(boolean isPractice, PastureGameData gameData) {
        if (isPractice) {
            userData.setPracticeData(gameData);
        } else {
            userData.setGameData(gameData);
        }
    }

    /**
     * 操作前处理
     */
    private void beforeOperateHandle(boolean isPractice, PastureGameData gameData, boolean useSkill, boolean isRevive) {
        if (!isRevive) {
            // 操作前保存当前数据
            LinkedList<PastureGameData> recentStepsData;
            if (isPractice) {
                recentStepsData = userData.getRecentStepsPracticeData();
            } else {
                recentStepsData = userData.getRecentStepsGameData();
            }
            if (recentStepsData.size() >= PastureMgr.MAX_KEEP_STEPS) {
                recentStepsData.removeFirst();
            }
            recentStepsData.addLast(gameData.clone());
            if (isPractice) {
                userData.setRecentStepsPracticeData(recentStepsData);
            } else {
                userData.setRecentStepsGameData(recentStepsData);
            }
        }
        // 清空移动消除数据
        gameData.setMoveStepResultList(new ArrayList<>());
        gameData.setFallHandlerCnt(0);
        gameData.setNeedCreateBossDataList(new ArrayList<>());
        // 清除积分相关
        gameData.setBaseScore(0);
        gameData.setChainClearCnt(0);
        // 操作日志相关
        gameData.setBeforeScore(gameData.getScore());
        gameData.setBeforeEnergy(gameData.getEnergy());
        gameData.setClearBlockOperateMap(new ConcurrentHashMap<>());
        gameData.setUseSkillAnimalId(0);
        // 添加一步操作
        addOneStep(gameData);
        // 操作后可生成的行数
        if (useSkill || isRevive) {
            gameData.setGenerateRow(0);
        } else {
            gameData.setGenerateRow(PastureMgr.OPERATE_GENERATE_ROW);
            // 未冻结才增加回合数
            if (gameData.getFreezeRound() == 0) {
                // 增加回合数
                gameData.setRound(gameData.getRound() + 1);
            }
        }
    }

    /**
     * 操作后处理
     */
    private void afterOperateHandler(boolean isPractice, PastureGameData gameData, boolean useSkill, boolean isRevive) {
        PastureConfig config = PastureMgr.getConfig();
        // 更新一下坐标
        updateBlockCoordinates(gameData);
        // 消除处理
        handlerFallAndClear(isPractice, gameData);
        // 处理完计算分数
        updateScore(isPractice, gameData);
        if (!useSkill && !isRevive && gameData.getFreezeRound() > 0) {
            gameData.setFreezeRound(gameData.getFreezeRound() - 1);
        }
        // 练习达到回合数就结束游戏
        if (isPractice) {
            if (gameData.getRound() >= config.getPasturePracticeRound()) {
                // 游戏结束
                gameData.setGameStatus(ePastureGameStatusType.Finished.getValue());
            }
        } else {
            // 最高回合
            userData.setMaxRound(Math.max(userData.getMaxRound(), gameData.getRound()));
            if (isGameRunning(gameData) && config.getPastureNormalRound() != 0 && gameData.getRound() >= config.getPastureNormalRound()) {
                // 等待通关
                gameData.setGameStatus(ePastureGameStatusType.WaitPassed.getValue());
            }
        }
        // 更新游戏数据
        updateGameData(isPractice, gameData);
        if (!isPractice) {
            // 添加操作日志
            AutoLogMgr.add(new LogPastureOperate(
                    player.getUserId(),
                    config.getActivityInfo().getActivityId(),
                    gameData.getRound(),
                    gameData.getBeforeScore(),
                    gameData.getScore() - gameData.getBeforeScore(),
                    gameData.getScore(),
                    JSON.toJSONString(gameData.getClearBlockOperateMap()),
                    gameData.getBeforeEnergy(),
                    gameData.getEnergy() - gameData.getBeforeEnergy(),
                    gameData.getEnergy(),
                    useSkill,
                    gameData.getUseSkillAnimalId(),
                    new Date()
            ));
        }
    }

    /**
     * 游戏通关（仅正式模式）
     */
    private void gamePassedHandler(PastureGameData gameData) {
        // 游戏通关
        gameData.setGameStatus(ePastureGameStatusType.Passed.getValue());
        // 消除所有的方块
        clearRow(gameData, 0, PastureMgr.MAX_HEIGHT - 1, true);
        // 处理完计算分数
        updateScore(false, gameData);
    }

    private void updateScore(boolean isPractice, PastureGameData gameData) {
        // 增加积分
        gameData.setScore(gameData.getScore() + calculateScore(gameData));
        // 记录最高积分
        if (!isPractice && gameData.getScore() >= userData.getMaxScore()) {
            // 最高积分
            userData.setMaxScore(gameData.getScore());
            // 积分排行榜
            player.notifyListener(eGamePlayerEventType.PastureMaxScoreRank.getValue(), new ValueParamArgs(userData.getMaxScore(), String.valueOf(gameData.getRound())));
            player.notifyListener(eGamePlayerEventType.PastureBronzeToken.getValue(), userData.getMaxScore());
            if (userData.isBuySilverToken()) {
                player.notifyListener(eGamePlayerEventType.PastureSilverToken.getValue(), userData.getMaxScore());
            }
            if (userData.isBuyGoldToken()) {
                player.notifyListener(eGamePlayerEventType.PastureGoldToken.getValue(), userData.getMaxScore());
            }
            // 同步用户数据
            syncUserData();
        }

    }


    /**
     * 计算积分
     */
    private long calculateScore(PastureGameData gameData) {
        // 计算分数
        // 单回合内连消的得分加成
        List<Integer> pasturePointUpChain = PastureMgr.getConfig().getPasturePointUpChain();
        int pointUpChainRate = 0;
        if (gameData.getChainClearCnt() > 0) {
            pointUpChainRate = pasturePointUpChain.get(Math.min(pasturePointUpChain.size() - 1, gameData.getChainClearCnt() - 1));
        }
        BigDecimal baseScore = BigDecimal.valueOf(gameData.getBaseScore());
        int addition = 1000 + pointUpChainRate;
        return baseScore.multiply(BigDecimal.valueOf(addition)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
    }


    /**
     * 添加一步操作（方便客户端表现用）
     */
    private void addOneStep(PastureGameData gameData) {
        // 如果最后一个数组为空，则不需要加
        if (gameData.getMoveStepResultList().size() > 0 && gameData.getMoveStepResultList().get(gameData.getMoveStepResultList().size() - 1).getPastureMoveBlockResultList().size() == 0) {
            return;
        }
        gameData.getMoveStepResultList().add(new PastureMoveStepResult());
    }

    /**
     * 往当前操作中加入移动数据
     */
    private void addMoveData(PastureGameData gameData, PastureMoveBlockResult moveResult) {
        PastureBlockData originBlockData = moveResult.getOriginBlockData();
        PastureBlockData targetBlockData = moveResult.getTargetBlockData();
        // 如果对象相等则不需要添加
        if (originBlockData != null && originBlockData.equals(targetBlockData)) {
            return;
        }
        PastureMoveStepResult pastureMoveStepResult = new PastureMoveStepResult();
        if (gameData.getMoveStepResultList().size() > 0) {
            pastureMoveStepResult = gameData.getMoveStepResultList().get(gameData.getMoveStepResultList().size() - 1);
        }
        pastureMoveStepResult.getPastureMoveBlockResultList().add(moveResult);
        pastureMoveStepResult.setScore(gameData.getScore());
        pastureMoveStepResult.setEnergy(gameData.getEnergy());
    }

    private void blockDataChange(PastureBlockData blockData, int targetY, int targetLeft, int targetRight) {
        PastureBlockData targetBlockData = blockData.clone();
        targetBlockData.setY(targetY);
        targetBlockData.setLeft(targetLeft);
        targetBlockData.setRight(targetRight);
        targetBlockData.setLength(targetRight - targetLeft + 1);
        blockDataChange(blockData, targetBlockData);
    }

    private void blockDataChange(PastureBlockData blockData, PastureBlockData targetBlockData) {
        blockData.setY(targetBlockData.getY());
        blockData.setLeft(targetBlockData.getLeft());
        blockData.setRight(targetBlockData.getRight());
        blockData.setLength(targetBlockData.getLength());
        blockData.setUseSkill(targetBlockData.isUseSkill());
        blockData.setScore(targetBlockData.getScore());
        blockData.setEnergy(targetBlockData.getEnergy());
        blockData.setExtraData(targetBlockData.getExtraData());
        blockData.setAnimalId(targetBlockData.getAnimalId());
    }


    /**
     * 生成对象(移动过程)
     */
    private PastureMoveBlockResult generateBlockDataChange(PastureBlockData blockData, int moveType) {
        PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
        moveResult.setOriginBlockData(null);
        moveResult.setTargetBlockData(blockData.clone());
        moveResult.setMoveType(moveType);
        return moveResult;
    }

    /**
     * 销毁对象(移动过程)
     */
    private PastureMoveBlockResult destroyBlockDataChange(PastureBlockData blockData, int moveType) {
        PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
        moveResult.setOriginBlockData(blockData.clone());
        moveResult.setTargetBlockData(null);
        moveResult.setMoveType(moveType);
        return moveResult;
    }

    /**
     * 判断游戏是否进行中
     */
    private boolean isGameRunning(PastureGameData gameData) {
        return gameData != null && gameData.getGameStatus() == ePastureGameStatusType.Running.getValue();
    }

    /**
     * 生成格子数据,初始化生成两行
     *
     * @param gameData 游戏数据
     */
    private void genBlockData(boolean isPractice, PastureGameData gameData) {
        if (!isGameRunning(gameData)) {
            return;
        }
        if (gameData.getFreezeRound() > 0) {
            return;
        }
        addOneStep(gameData);
        // 隐藏设定，在每回合开始新行出来时判定，若蛇用了技能或者吞食其他动物使其长度大于原本自身的2格后，则尾部-1格。直至恢复到基本的2格
        List<PastureBlockData> needCreateSnakeBlock = new ArrayList<>();
        for (List<PastureBlockData> blockDataList : gameData.getBlockDataList()) {
            for (PastureBlockData blockData : blockDataList) {
                if (blockData.getAnimalId() == ePastureSkillType.Snake.getValue()) {
                    PastureAnimalConfig animalConfig = PastureMgr.getConfig().getAnimalConfigMap().get(blockData.getAnimalId());
                    if (blockData.getLength() > animalConfig.getSize()) {
                        // 记录移动数据
                        addMoveData(gameData, destroyBlockDataChange(blockData, ePastureGameMoveType.SnakeCutDown.getValue()));
                        // 尾部缩短
                        cutTailBlock(blockData, 1);
                        needCreateSnakeBlock.add(blockData);
                    }
                }
            }
        }
        if (needCreateSnakeBlock.size() > 0) {
            addOneStep(gameData);
            needCreateSnakeBlock.forEach(t -> addMoveData(gameData, generateBlockDataChange(t, ePastureGameMoveType.SnakeCutDown.getValue())));
        }
        // 初始化生成
        while (gameData.getInitBlockDataList().size() > 0) {
            createOneRowBlockData(isPractice, gameData, true);
        }
        while (gameData.getGenerateRow() > 0) {
            createOneRowBlockData(isPractice, gameData, false);
            // 本次操作可生成数据
            gameData.setGenerateRow(gameData.getGenerateRow() - 1);
        }
        // 生成后处理后续操作
        handlerFallAndClear(isPractice, gameData);
    }

    /**
     * 缩放尾部len格
     */
    private void cutTailBlock(PastureBlockData blockData, int cutLen) {
        if (cutLen >= blockData.getLength()) {
            return;
        }
        // 获取动物朝向
        if (blockData.getDirection() == 1) {
            // 朝右缩左
            blockDataChange(blockData, blockData.getY(), blockData.getLeft() + cutLen, blockData.getRight());
        } else {
            // 朝左缩右
            blockDataChange(blockData, blockData.getY(), blockData.getLeft(), blockData.getRight() - cutLen);
        }
    }


    /**
     * 生成一行数据
     *
     * @param gameData 游戏数据
     */
    private void createOneRowBlockData(boolean isPractice, PastureGameData gameData, boolean init) {
        if (!isGameRunning(gameData)) {
            return;
        }
        // 移除首行数据
        if (gameData.getBlockDataList().size() >= PastureMgr.MAX_HEIGHT) {
            List<PastureBlockData> blockDataList = gameData.getBlockDataList().get(0);
            // 判断是否游戏结束
            // 如果这一行有数据则游戏结束
            if (blockDataList.size() > 0) {
                if (isPractice) {
                    // 设置游戏为结束状态
                    gameData.setGameStatus(ePastureGameStatusType.Finished.getValue());
                } else {
                    // 设置游戏为等待复活状态
                    gameData.setGameStatus(ePastureGameStatusType.Revive.getValue());
                }
                return;
            }
            gameData.getBlockDataList().remove(0);
        }
        // 操作前生成预览数据
        if (gameData.getPreviewBlockDataList().size() == 0) {
            createPreviewBlockRow(gameData);
        }
        if (init) {
            // 将预览的数据首行,加到地图上
            if (gameData.getInitBlockDataList().size() > 0) {
                addLastRowData(gameData, gameData.getInitBlockDataList().remove(0));
            }
        } else {
            // 将预览的数据首行,加到地图上
            if (gameData.getPreviewBlockDataList().size() > 0) {
                addLastRowData(gameData, gameData.getPreviewBlockDataList().remove(0));
            }
        }
        // 操作后补齐预览数据
        createPreviewBlockRow(gameData);
        // 更新坐标
        updateBlockCoordinates(gameData);
    }


    /**
     * 添加数据到末行
     */
    private void addLastRowData(PastureGameData gameData, List<PastureBlockData> blockDataList) {
        gameData.getBlockDataList().add(blockDataList);
    }

    /**
     * 添加数据到首行
     */
    private void addFirstRowData(PastureGameData gameData, List<PastureBlockData> blockDataList) {
        gameData.getBlockDataList().add(0, blockDataList);
    }


    /**
     * 判断地图是否为空
     */
    private boolean isMapEmpty(PastureGameData gameData) {
        return gameData.getBlockDataList().stream().noneMatch(dataList -> dataList.size() > 0);
    }

    /**
     * 区间[left,right]内是否都为空格子
     */
    private boolean isAllSpaceInRange(PastureGameData gameData, int y, int left, int right) {
        // 获取所有的空格
        List<Integer> emptyIndex = getEmptyIndex(gameData, y);
        // 判断区间[left,right]内是否都为空格
        return IntStream.rangeClosed(left, right).allMatch(emptyIndex::contains);
    }

    /**
     * 获取（x,y）的格子对象
     */
    private PastureBlockData getBlockData(PastureGameData gameData, int x, int y) {
        if (x < 0 || x >= PastureMgr.MAX_WIDTH) {
            return null;
        }
        if (y < 0 || y >= PastureMgr.MAX_HEIGHT) {
            return null;
        }
        List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
        for (PastureBlockData blockData : dataList) {
            if (blockData.getLeft() <= x && blockData.getRight() >= x) {
                return blockData;
            }
        }
        return null;
    }

    /**
     * 获取(x1-x2,y)的所有格子对象(包含重叠的格子)
     */
    private List<PastureBlockData> getBlockDataList(PastureGameData gameData, int x1, int x2, int y, PastureBlockData noIncludeBlockData) {
        List<PastureBlockData> list = new ArrayList<>();
        if (y < 0 || y >= PastureMgr.MAX_HEIGHT) {
            return list;
        }
        List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
        for (int x = x1; x <= x2; x++) {
            for (PastureBlockData blockData : dataList) {
                if (blockData.getLeft() <= x && blockData.getRight() >= x) {
                    if (!blockData.equals(noIncludeBlockData) && !list.contains(blockData)) {
                        list.add(blockData);
                    }
                }
            }
        }
        return list;
    }

    /**
     * 下落操作,从下往上,消除操作
     */
    private void handlerFallAndClear(boolean isPractice, PastureGameData gameData) {
        if (!isGameRunning(gameData)) {
            return;
        }
        gameData.setFallHandlerCnt(gameData.getFallHandlerCnt() + 1);
        if (gameData.getFallHandlerCnt() > 1000) {
            return;
        }
        // 添加一步操作
        addOneStep(gameData);
        // 从下往上,判断当前对象的下方是否为空格子
        // 只要还有掉落的就继续判断
        for (int i = 0; i < 100; i++) {
            if (!continueFall(gameData)) {
                break;
            }
        }
        // 掉落后更新下坐标
        updateBlockCoordinates(gameData);

        // 掉落后检测是否有可消除的
        boolean isClear = false;
        int clearRowIdx;
        while ((clearRowIdx = getClearRowIdx(gameData)) != -1) {
            // 有可消除操作
            clearRowBlock(gameData, clearRowIdx, false);
            isClear = true;
        }
        afterClear(gameData);
        if (isClear) {
            // 下落前先计算下积分
            updateScore(isPractice, gameData);
            // 清除积分计算相关
            gameData.setBaseScore(0);
            // 更新坐标
            updateBlockCoordinates(gameData);
            // 消除后下坠
            handlerFallAndClear(isPractice, gameData);
        }

        if (isMapEmpty(gameData)) {
            // 如果盘面数据为空,则清除冻结的回合,生成两行数据
            gameData.setFreezeRound(0);
            gameData.setGenerateRow(PastureMgr.CLEAR_GENERATE_ROW);
        }
        if (gameData.getGenerateRow() > 0) {
            // 如果还有生成回合,则生成生成数据
            genBlockData(isPractice, gameData);
        }
    }

    /**
     * 清除后操作
     */
    private void afterClear(PastureGameData gameData) {
        if (gameData.getNeedCreateBossDataList().size() > 0) {
            addOneStep(gameData);
            for (PastureBlockData blockData : gameData.getNeedCreateBossDataList()) {
                // 添加对象
                addMoveData(gameData, generateBlockDataChange(blockData, ePastureGameMoveType.Default.getValue()));
            }
            gameData.getNeedCreateBossDataList().clear();
        }
    }

    /**
     * 掉落操作
     * 是否需要继续处理掉落（有掉落需要继续检测掉落）
     */
    private boolean continueFall(PastureGameData gameData) {
        for (int y = gameData.getBlockDataList().size() - 1; y >= 0; y--) {
            List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
            for (PastureBlockData blockData : dataList) {
                if (fallDown(gameData, blockData.getY(), blockData)) {
                    return true;
                }
            }
        }
        return false;
    }

    private int fallRow(PastureGameData gameData, int y, PastureBlockData blockData) {
        int tempY = y;
        // 检测下一行是否能掉落
        while (tempY + 1 < PastureMgr.MAX_HEIGHT && isAllSpaceInRange(gameData, tempY + 1, blockData.getLeft(), blockData.getRight())) {
            tempY = tempY + 1;
        }
        return tempY;
    }

    /**
     * 下落
     */
    private void fall(PastureGameData gameData, int originY, int targetY, PastureBlockData blockData) {
        if (originY < 0 || originY >= PastureMgr.MAX_HEIGHT || targetY < 0 || targetY >= PastureMgr.MAX_HEIGHT) {
            return;
        }
        // 记录移动过程
        PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
        moveResult.setOriginBlockData(blockData.clone());
        // 删除上面的对象
        removeBlockData(gameData, originY, blockData);
        // 对象信息更改
        blockDataChange(blockData, targetY, blockData.getLeft(), blockData.getRight());
        // 添加下面的对象
        addBlockData(gameData, targetY, blockData);
        moveResult.setTargetBlockData(blockData.clone());
        moveResult.setMoveType(ePastureGameMoveType.Default.getValue());
        addMoveData(gameData, moveResult);
    }


    /**
     * 下落到底
     */
    private boolean fallDown(PastureGameData gameData, int y, PastureBlockData blockData) {
        int fallY = fallRow(gameData, y, blockData);
        boolean isFall = fallY > y;
        if (isFall) {
            fall(gameData, y, fallY, blockData);
        }
        return isFall;
    }


    /**
     * 从下往上判断是否有可消除的行,有的话返回行索引,没有返回-1
     */
    private int getClearRowIdx(PastureGameData gameData) {
        for (int i = gameData.getBlockDataList().size() - 1; i >= 0; i--) {
            if (getEmptyIndex(gameData, i).size() == 0) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 清除最下两行数据
     */
    private void clearRow(PastureGameData gameData, int y1, int y2, boolean isForce) {
        addOneStep(gameData);
        for (int y = y1; y <= y2; y++) {
            clearRowBlock(gameData, y, isForce);
        }
        afterClear(gameData);
    }

    /**
     * 消除一行
     *
     * @param isForce 是否强制消除（无视boss）
     */
    private void clearRowBlock(PastureGameData gameData, int clearRowIdx, boolean isForce) {
        if (clearRowIdx < 0 || clearRowIdx >= PastureMgr.MAX_HEIGHT) {
            return;
        }
        long sumScore = 0;
        long sumEnergy = 0;
        // 获取要消除的行
        List<PastureBlockData> blockDataList = gameData.getBlockDataList().get(clearRowIdx);
        // 判断当前有没有boss存在
        boolean canClearRow = true;
        for (PastureBlockData blockData : blockDataList) {
            if (blockData.getAnimalId() == ePastureAnimalType.Cow.getValue() && blockData.getLength() > 1) {
                canClearRow = false;
                break;
            }
        }
        Iterator<PastureBlockData> iterator = gameData.getBlockDataList().get(clearRowIdx).iterator();
        while (iterator.hasNext()) {
            PastureBlockData blockData = iterator.next();
            // 消除对象
            if (!isForce) {
                addMoveData(gameData, destroyBlockDataChange(blockData, ePastureGameMoveType.Default.getValue()));
            } else {
                addMoveData(gameData, destroyBlockDataChange(blockData, ePastureGameMoveType.ForceClear.getValue()));
            }
            // 存在boss且长度大于1，变短，其他消除    新增（冻结的回合内，可直接消除）
            if (!isForce && gameData.getFreezeRound() == 0 && !canClearRow && blockData.getAnimalId() == ePastureAnimalType.Cow.getValue() && blockData.getLength() > 1) {
                // 尾部缩短
                cutTailBlock(blockData, 1);
                gameData.getNeedCreateBossDataList().add(blockData.clone());
            } else {
                // 只有消除时加分
                sumScore += blockData.getScore() + blockData.getExtraScore();
                sumEnergy += blockData.getEnergy() + blockData.getExtraEnergy();
                // 记录消除日志
                addClearBlockRecord(gameData, blockData.getAnimalId());
                gameData.setTotalGetEnergy(gameData.getTotalGetEnergy() + blockData.getEnergy() + blockData.getExtraEnergy());
                iterator.remove();
            }
        }
        // 增加积分
        gameData.setBaseScore(gameData.getBaseScore() + sumScore);
        // 获取当前能量的上限
        int curMaxEnergy = PastureMgr.getSkillEnergyMax(gameData.getUseSkillCnt());
        // 获取下一条的能量上限
        int nextMaxEnergy = PastureMgr.getSkillEnergyMax(gameData.getUseSkillCnt() + 1);
        int totalMaxEnergy = curMaxEnergy + nextMaxEnergy;
        // 能量未满时才增加
        if (gameData.getEnergy() < totalMaxEnergy) {
            // 增加能量
            gameData.setEnergy(Math.min(totalMaxEnergy, gameData.getEnergy() + sumEnergy));
        }
        // 强制消除不计入连消
        if (!isForce){
            // 单回合连消
            gameData.setChainClearCnt(gameData.getChainClearCnt() + 1);
        }
    }

    /**
     * 消除记录
     */
    private void addClearBlockRecord(PastureGameData gameData, int animalId) {
        gameData.getClearBlockTotalMap().put(animalId, gameData.getClearBlockTotalMap().getOrDefault(animalId, 0) + 1);
        gameData.getClearBlockOperateMap().put(animalId, gameData.getClearBlockOperateMap().getOrDefault(animalId, 0) + 1);
    }


    /**
     * 更新坐标
     */
    private void updateBlockCoordinates(PastureGameData gameData) {
        addOneStep(gameData);
        // 消除结束后头部补齐地图
        while (gameData.getBlockDataList().size() < PastureMgr.MAX_HEIGHT) {
            addFirstRowData(gameData, new ArrayList<>());
        }
        for (int i = 0; i < gameData.getBlockDataList().size(); i++) {
            List<PastureBlockData> blockDataList = gameData.getBlockDataList().get(i);
            // 更新纵坐标
            for (PastureBlockData blockData : blockDataList) {
                // 记录移动过程
                PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
                moveResult.setOriginBlockData(blockData.clone());
                blockDataChange(blockData, i, blockData.getLeft(), blockData.getRight());
                moveResult.setTargetBlockData(blockData.clone());
                moveResult.setMoveType(ePastureGameMoveType.Default.getValue());
                addMoveData(gameData, moveResult);
            }
            // 按左边界left排序
            blockDataList.sort(Comparator.comparingInt(PastureBlockData::getLeft));
        }
    }

    /**
     * 获取可生成的模板回合
     */
    private int getCanGenRound(int genRound) {
        int round = 0;
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || config.getModuleConfigMap() == null) {
            return round;
        }
        List<PastureModuleConfig> list = new ArrayList<>(config.getModuleConfigMap().values());
        // 按round升序排序
        list.sort(Comparator.comparingLong(PastureModuleConfig::getRound));
        for (PastureModuleConfig moduleConfig : list) {
            // 需要提前生成预览数据
            if (genRound > moduleConfig.getRound()) {
                round = moduleConfig.getRound();
            }
        }
        return round;
    }

    /**
     * 根据分数获取要生成的组合
     */
    private List<List<Integer>> getAnimalIdListByRound(PastureGameData gameData, int genRound) {
        List<List<Integer>> animalIdList = new ArrayList<>();
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || config.getModuleConfigMap() == null) {
            return null;
        }
        // 模板库
        String moduleListConfig = null;
        // 动物配置
        String animalListConfig = null;
        List<PastureModuleConfig> list = new ArrayList<>(config.getModuleConfigMap().values());
        // 按round升序排序
        list.sort(Comparator.comparingLong(PastureModuleConfig::getRound));
        for (PastureModuleConfig moduleConfig : list) {
            // 需要提前生成预览数据
            if (genRound > moduleConfig.getRound()) {
                moduleListConfig = moduleConfig.getModuleList();
                animalListConfig = moduleConfig.getAnimalList();
                gameData.setGenRound(moduleConfig.getRound());
            }
        }
        if (moduleListConfig == null || animalListConfig == null) {
            return null;
        }

        // 下面开始抽
        // 先根据权重抽模板
        String moduleStr = "";
        // 权重抽取
        List<String> moduleList = StringUtils.stringToStringList(moduleListConfig, "\\|");
        // 总权重
        int sumWeight = 0;
        for (String s : moduleList) {
            String[] split = s.split(":");
            sumWeight += Integer.parseInt(split[1]);
        }
        // 随机一个权重
        int randomWeight = (int) (Math.random() * sumWeight);
        // 当前权重
        int curWeight = 0;
        for (String s : moduleList) {
            String[] split = s.split(":");
            curWeight += Integer.parseInt(split[1]);
            if (randomWeight < curWeight) {
                moduleStr = split[0];
                break;
            }
        }

        // 获取到模板moduleStr后开始抽动物
        // 1=3;3=1,1=2;3=2
        // 分组
        List<String> groupModule = StringUtils.stringToStringList(moduleStr, ",");
        for (String module : groupModule) {
            List<Integer> animalRowList = new ArrayList<>();
            // 1=3;3=1 => 宽度1的动物3只, 宽度3的动物1只
            int totalWidth = 0;
            List<String> rowData = StringUtils.stringToStringList(module, ";");
            for (String rowDatum : rowData) {
                String[] split = rowDatum.split("=");
                int width = Integer.parseInt(split[0]);
                int num = Integer.parseInt(split[1]);
                // 一行动物的配置
                animalRowList.addAll(getAnimalListWithWidth(width, num, animalListConfig));
                totalWidth += width * num;
            }
            // 补齐
            int needLen = PastureMgr.MAX_WIDTH - totalWidth;
            // 补齐格子
            for (int i = 0; i < needLen; i++) {
                animalRowList.add(0);
            }
            Collections.shuffle(animalRowList);
            animalIdList.add(animalRowList);
        }
        return animalIdList;
    }

    /**
     * 根据动物宽度和数量获取组合
     *
     * @param width            宽度
     * @param num              数量
     * @param animalListConfig 动物权重配置
     */
    private List<Integer> getAnimalListWithWidth(int width, int num, String animalListConfig) {
        List<Integer> ans = new ArrayList<>();
        // 根据宽度获取动物id
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || config.getAnimalConfigMap() == null) {
            return ans;
        }
        List<Integer> animalIdList = new ArrayList<>();
        for (PastureAnimalConfig animalConfig : config.getAnimalConfigMap().values()) {
            // 找出对应宽度的动物
            if (animalConfig.getSize() == width) {
                animalIdList.add(animalConfig.getAnimalId());
            }
        }
        // 计算总权重
        List<Integer> configList = StringUtils.stringToIntegerList(animalListConfig, "\\|");
        // 总权重
        int sumWeight = 0;
        for (int i = 0; i < configList.size(); i++) {
            if (animalIdList.contains(i + 1)) {
                sumWeight += configList.get(i);
            }
        }

        // 开始随机
        for (int cnt = 0; cnt < num; cnt++) {
            // 随机一个权重
            int randomWeight = (int) (Math.random() * sumWeight);
            // 当前权重
            int curWeight = 0;
            for (int i = 0; i < configList.size(); i++) {
                if (animalIdList.contains(i + 1)) {
                    curWeight += configList.get(i);
                    if (randomWeight < curWeight) {
                        ans.add(i + 1);
                        break;
                    }
                }
            }

        }
        return ans;
    }


    /**
     * 生成n行预览数据
     *
     * @param gameData 游戏数据
     */
    private void createPreviewBlockRow(PastureGameData gameData) {
        PastureConfig config = PastureMgr.getConfig();
        // 判断下有没有需要生成的预览数据
        if (gameData.getBeforeGenBlockDataList().size() > 0) {
            gameData.getPreviewBlockDataList().add(gameData.getBeforeGenBlockDataList().remove(0));
            return;
        }
        // 获取当前回合
        int curRound = gameData.getRound();
        // 生成的是下一回合的预览数据
        int nextRound = curRound + 1;
        // 如果下一回合是boss关卡，生成boss
        if (config.getPastureBossRefresh().contains(nextRound) && !gameData.getGenBossRoundList().contains(nextRound)) {
            // 预览数据塞入boss数据
            List<Integer> bossRowAnimal = new ArrayList<>();
            int boosAnimalId = ePastureAnimalType.Cow.getValue();
            bossRowAnimal.add(boosAnimalId);
            // 计算需要补齐的动物
            PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(boosAnimalId);
            // 补齐
            int needLen = PastureMgr.MAX_WIDTH - animalConfig.getSize();
            // 补齐格子
            for (int i = 0; i < needLen; i++) {
                bossRowAnimal.add(0);
            }
            Collections.shuffle(bossRowAnimal);
            genPreviewBlockData(gameData, bossRowAnimal, true);
            // 记录已生成的boss回合
            gameData.getGenBossRoundList().add(nextRound);
            return;
        }
        // 有数据暂不生成
        if (gameData.getPreviewBlockDataList().size() > 0 && getCanGenRound(nextRound) == gameData.getGenRound()) {
            return;
        }
        if (gameData.getPreviewBlockDataList().size() > 0 && getCanGenRound(nextRound) != gameData.getGenRound()) {
            // 清空预览数据
            gameData.getPreviewBlockDataList().clear();
        }
        // 获取要生成的组合
        List<List<Integer>> allAnimalIdRowList = getAnimalIdListByRound(gameData, nextRound);
        if (allAnimalIdRowList == null) {
            return;
        }
        for (List<Integer> animalIdRowList : allAnimalIdRowList) {
            genPreviewBlockData(gameData, animalIdRowList, false);
        }
    }

    /**
     * 生成详细数据
     */
    private void genPreviewBlockData(PastureGameData gameData, List<Integer> animalIdRowList, boolean addHead) {
        PastureConfig config = PastureMgr.getConfig();
        // 添加坐标
        int x = 0;
        List<PastureBlockData> blockDataList = new ArrayList<>();
        for (Integer animalId : animalIdRowList) {
            // 空格类型不生成对象
            if (animalId == 0) {
                x += 1;
                continue;
            }
            PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
            PastureBlockData blockData = new PastureBlockData();
            blockData.setAnimalId(animalId);
            blockData.setLength(animalConfig.getSize());
            blockData.setLeft(x);
            x += blockData.getLength();
            blockData.setRight(x - 1);
            // 预览数据默认纵坐标在最底下
            blockData.setY(PastureMgr.MAX_HEIGHT);
            // 根据晋升次数获取得分
            PastureAnimalData animalData = userData.getAnimalDataMap().get(animalId);
            int promoteCnt = 0;
            if (animalData != null) {
                promoteCnt = animalData.getPromoteCnt();
            }
            blockData.setScore(animalConfig.getPoint().get(Math.min(promoteCnt, animalConfig.getPoint().size() - 1)));
            blockData.setEnergy(animalConfig.getEnergy());
            // 添加动物朝向(默认向左)
            blockData.setDirection(-1);
            if (animalId == ePastureAnimalType.Cow.getValue()) {
                Random random = new Random();
                blockData.setDirection(random.nextBoolean() ? 1 : -1);
            }
            blockDataList.add(blockData);
        }
        if (addHead) {
            gameData.getPreviewBlockDataList().add(0, blockDataList);
        } else {
            gameData.getPreviewBlockDataList().add(blockDataList);
        }
    }


    /**
     * 获取指定行的空格索引
     */
    private List<Integer> getEmptyIndex(PastureGameData gameData, int y) {
        return getEmptyIndex(gameData, y, 0, PastureMgr.MAX_WIDTH - 1);
    }

    /**
     * 获取指定行区间[left,right]的空格索引
     */
    private List<Integer> getEmptyIndex(PastureGameData gameData, int y, int left, int right) {
        return getBlockIndex(gameData, y, left, right, true);
    }

    /**
     * 获取指定行的非空格索引
     */
    private List<Integer> getNotEmptyIndex(PastureGameData gameData, int y) {
        return getNotEmptyIndex(gameData, y, 0, PastureMgr.MAX_WIDTH - 1);
    }

    /**
     * 获取指定行区间[left,right]的非空格索引
     */
    private List<Integer> getNotEmptyIndex(PastureGameData gameData, int y, int left, int right) {
        return getBlockIndex(gameData, y, left, right, false);
    }

    /**
     * 获取指定行区间[left,right]的格子索引
     */
    private List<Integer> getBlockIndex(PastureGameData gameData, int y, int left, int right, boolean isEmpty) {
        List<Integer> blockIndex = new ArrayList<>();
        if (y < 0 || y >= PastureMgr.MAX_HEIGHT) {
            return blockIndex;
        }
        if (left < 0 || left >= PastureMgr.MAX_WIDTH || right < 0 || right >= PastureMgr.MAX_WIDTH) {
            return blockIndex;
        }
        List<PastureBlockData> blockDataList = gameData.getBlockDataList().get(y);
        for (int i = left; i <= right; i++) {
            boolean flag = isEmpty;
            for (PastureBlockData blockData : blockDataList) {
                if (i >= blockData.getLeft() && i <= blockData.getRight()) {
                    flag = !flag;
                    break;
                }
            }
            if (flag) {
                blockIndex.add(i);
            }
        }
        return blockIndex;
    }

    /**
     * 每日重置
     */
    public void resetOneDay() {
        if (!preCheck(false)) {
            return;
        }
        long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp();
        if (userData.getResetTime() < zeroTime) {
            userData.setResetTime(zeroTime);
            userData.setTodayTimes(0);
        }
    }

    /**
     * 移除指定行的对象
     */
    private void removeBlockData(PastureGameData gameData, int y, PastureBlockData blockData) {
        if (y < 0 || y >= PastureMgr.MAX_HEIGHT) {
            return;
        }
        List<PastureBlockData> blockDataList = gameData.getBlockDataList().get(y);
        if (!blockDataList.contains(blockData)) {
            return;
        }
        // 移除
        blockDataList.remove(blockData);
        // 按左边界left排序
        blockDataList.sort(Comparator.comparingInt(PastureBlockData::getLeft));
    }

    /**
     * 添加动物对象
     */
    private void addBlockData(PastureGameData gameData, int y, int left, int right, int animalId) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || config.getAnimalConfigMap() == null) {
            return;
        }
        PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
        if (animalConfig == null) {
            return;
        }
        addOneStep(gameData);
        PastureBlockData blockData = new PastureBlockData();
        blockData.setAnimalId(animalId);
        blockData.setY(y);
        blockData.setLeft(left);
        blockData.setRight(right);
        blockData.setLength(right - left + 1);
        // 添加动物属性
        blockData.setEnergy(animalConfig.getEnergy());
        // 根据晋升次数获取得分
        PastureAnimalData animalData = userData.getAnimalDataMap().get(animalId);
        int promoteCnt = 0;
        if (animalData != null) {
            promoteCnt = animalData.getPromoteCnt();
        }
        blockData.setScore(animalConfig.getPoint().get(Math.min(promoteCnt, animalConfig.getPoint().size() - 1)));
        // 把动物放进去
        addBlockData(gameData, y, blockData);
        // 生成新对象
        addMoveData(gameData, generateBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
    }


    /**
     * 往指定行塞格子对象
     */
    private void addBlockData(PastureGameData gameData, int y, PastureBlockData blockData) {
        if (y < 0 || y >= PastureMgr.MAX_HEIGHT) {
            return;
        }
        List<PastureBlockData> blockDataList = gameData.getBlockDataList().get(y);
        // 获取当前行的空格
        List<Integer> emptyIndex = getEmptyIndex(gameData, y);
        // 检测能否放得下
        for (int i = blockData.getLeft(); i <= blockData.getRight(); i++) {
            if (i < 0 || i >= PastureMgr.MAX_WIDTH) {
                return;
            }
            if (!emptyIndex.contains(i)) {
                return;
            }
        }
        // 放入
        blockDataList.add(blockData);
        // 按左边界left排序
        blockDataList.sort(Comparator.comparingInt(PastureBlockData::getLeft));
    }

    /**
     * 动物晋升更新游戏数据的积分
     */
    private void animalPromoteUpdateBaseScore(int animalId) {
        // 游戏数据
        animalPromoteUpdateBaseScore(userData.getGameData(), animalId);
        // 练习模式下，动物基础分不受晋升星级影响
//        animalPromoteUpdateBaseScore(userData.getPracticeData(), animalId);
        // 同步游戏数据
        syncUserData();
    }

    private void animalPromoteUpdateBaseScore(PastureGameData gameData, int animalId) {
        PastureConfig config = PastureMgr.getConfig();
        if (config == null || config.getAnimalConfigMap() == null) {
            return;
        }
        PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
        if (animalConfig == null) {
            return;
        }
        if (!isGameRunning(gameData)) {
            return;
        }
        // 获取晋升的积分
        PastureAnimalData pastureAnimalData = userData.getAnimalDataMap().get(animalId);
        // 获取基础得分
        int baseScore = animalConfig.getPoint().get(pastureAnimalData.getPromoteCnt());
        // 游戏数据
        for (List<PastureBlockData> blockDataList : gameData.getBlockDataList()) {
            animalPromoteUpdateBaseScore(animalId, baseScore, blockDataList);
        }
        // 预览数据
        for (List<PastureBlockData> blockDataList : gameData.getPreviewBlockDataList()) {
            animalPromoteUpdateBaseScore(animalId, baseScore, blockDataList);
        }
    }

    private void animalPromoteUpdateBaseScore(int animalId, int baseScore, List<PastureBlockData> blockDataList) {
        for (PastureBlockData blockData : blockDataList) {
            if (blockData.getAnimalId() != animalId) {
                continue;
            }
            // 猪特殊处理
            if (animalId == ePastureAnimalType.Pig.getValue()) {
                PasturePigExtraData extraData = new PasturePigExtraData();
                if (blockData.getExtraData() != null && blockData.getExtraData() instanceof PasturePigExtraData) {
                    extraData = (PasturePigExtraData) blockData.getExtraData();
                }
                // 获取本体尺寸
                int originSize = extraData.getOriginSize();
                if (originSize > 0) {
                    blockData.setScore(baseScore / originSize);
                } else {
                    blockData.setScore(baseScore);
                }
            } else {
                blockData.setScore(baseScore);
            }
        }
    }


    // ==========================技能处理=================================

    /**
     * 小鸡快跑
     * 朝相邻空格较多一侧移动，踩空时下落，着陆后继续移动，碰壁{0}次停止
     */
    private void skillOfChicken(PastureGameData gameData, int animalId, boolean isRepeat) {
        // 获取技能配置
        PastureConfig config = PastureMgr.getConfig();
        PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
        if (animalConfig == null) {
            return;
        }
        int skillId = animalConfig.getSkillId();
        PastureSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return;
        }
        //  碰壁X次后停止
        int stopLimit = Integer.parseInt(skillConfig.getSkillParam().split("\\|")[0]) / 1000;
        // 获取所有的小鸡
        List<PastureBlockData> allChickenList = new ArrayList<>();
        for (int y = 0; y < gameData.getBlockDataList().size(); y++) {
            List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
            for (PastureBlockData blockData : dataList) {
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                // 移动前清一下
                blockData.setExtraData(new PastureChickenExtraData());
                allChickenList.add(blockData);
            }
        }
        // 防止死循环
        int loopTimes = 0;
        while (!allChickenStop(allChickenList)) {
            if (loopTimes++ > 1000) {
                break;
            }
            // 开始移动
            for (PastureBlockData blockData : allChickenList) {
                checkChickenDirection(gameData, blockData);
                PastureChickenExtraData extraData = new PastureChickenExtraData();
                if (blockData.getExtraData() != null && blockData.getExtraData() instanceof PastureChickenExtraData) {
                    extraData = (PastureChickenExtraData) blockData.getExtraData();
                }
                if (extraData.isStop()) {
                    continue;
                }
                int targetLeft = blockData.getLeft();
                int targetRight = blockData.getRight();
                while (!extraData.isStop()) {
                    // 根据移动方向判断是否能移动
                    if (blockData.getDirection() == -1) {
                        // 向左移动
                        if (isAllSpaceInRange(gameData, blockData.getY(), targetLeft - 1, targetRight - 1)) {
                            targetLeft = targetLeft - 1;
                            targetRight = targetRight - 1;
                        } else {
                            // 不能移动,计算碰壁次数
                            extraData.setStopCnt(extraData.getStopCnt() + 1);
                            if (extraData.getStopCnt() >= stopLimit) {
                                extraData.setStop(true);
                            }
                            // 碰壁先跳出此次循环
                            blockData.setExtraData(extraData);
                            break;
                        }
                    } else {
                        // 向右移动
                        if (isAllSpaceInRange(gameData, blockData.getY(), targetLeft + 1, targetRight + 1)) {
                            targetLeft = targetLeft + 1;
                            targetRight = targetRight + 1;
                        } else {
                            // 不能移动,计算碰壁次数
                            extraData.setStopCnt(extraData.getStopCnt() + 1);
                            if (extraData.getStopCnt() >= stopLimit) {
                                extraData.setStop(true);
                            }
                            // 碰壁先跳出此次循环
                            blockData.setExtraData(extraData);
                            break;
                        }
                    }
                    // 记录下移动前坐标
                    int beforeMoveY = blockData.getY();
                    int beforeMoveLeft = blockData.getLeft();
                    int beforeMoveRight = blockData.getRight();
                    // 记录移动过程
                    PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
                    moveResult.setOriginBlockData(blockData.clone());
                    blockData.setExtraData(extraData);
                    blockDataChange(blockData, blockData.getY(), targetLeft, targetRight);
                    moveResult.setTargetBlockData(blockData.clone());
                    moveResult.setMoveType(ePastureGameMoveType.Skill.getValue());
                    addMoveData(gameData, moveResult);
                    // 移动时生成一只蛋壳鸡
                    addBlockData(gameData, beforeMoveY, beforeMoveLeft, beforeMoveRight, ePastureAnimalType.ChickenEgg.getValue());
                    // 下落
                    // 可下落的高度
                    int fallRow = fallRow(gameData, blockData.getY(), blockData);
                    while (fallRow > blockData.getY()) {
                        // 掉落时增加一步
                        addOneStep(gameData);
                        // 记录下掉落前坐标
                        int beforeFallY = blockData.getY();
                        int beforeFallLeft = blockData.getLeft();
                        int beforeFallRight = blockData.getRight();
                        // 掉落
                        fall(gameData, blockData.getY(), blockData.getY() + 1, blockData);
                        // 掉落时生成一只蛋壳鸡
                        addBlockData(gameData, beforeFallY, beforeFallLeft, beforeFallRight, ePastureAnimalType.ChickenEgg.getValue());
                        // 掉落后增加一步
                        addOneStep(gameData);
                    }
                }
                // 未停止移动
                if (!extraData.isStop()) {
                    addOneStep(gameData);
                }
            }
        }
    }

    private void checkChickenDirection(PastureGameData gameData, PastureBlockData blockData) {
        PastureChickenExtraData extraData = new PastureChickenExtraData();
        if (blockData.getExtraData() != null && blockData.getExtraData() instanceof PastureChickenExtraData) {
            extraData = (PastureChickenExtraData) blockData.getExtraData();
        }
        // 获取左侧的空格数量
        int leftCnt = 0;
        List<Integer> leftEmptyBlockList = getEmptyIndex(gameData, blockData.getY(), 0, blockData.getLeft() - 1);
        int tempLeft = blockData.getLeft();
        while (leftEmptyBlockList.contains(tempLeft - 1)) {
            leftCnt++;
            tempLeft = tempLeft - 1;
        }
        // 获取右侧的空格数量
        int rightCnt = 0;
        List<Integer> rightEmptyBlockList = getEmptyIndex(gameData, blockData.getY(), blockData.getRight() + 1, PastureMgr.MAX_WIDTH - 1);
        int tempRight = blockData.getRight();
        while (rightEmptyBlockList.contains(tempRight + 1)) {
            rightCnt++;
            tempRight = tempRight + 1;
        }
        // 判断方向
        int direction;
        boolean isStop;
        // 场上所有鸡，各自朝着与自身相邻空格较多的一侧(左/右)
        if (leftCnt >= rightCnt) {
            direction = -1;
            isStop = false;
        } else {
            direction = 1;
            isStop = false;
        }
        // 若两侧(左/右)都没有相邻空格，则静止不动
        if (leftCnt == 0 && rightCnt == 0) {
            isStop = true;
        }
        // 设置方向
        blockData.setDirection(direction);
        extraData.setStop(isStop);
        blockData.setExtraData(extraData);
    }


    /**
     * 所有触发技能的鸡是否都停止移动了
     */
    private boolean allChickenStop(List<PastureBlockData> allChickenList) {
        boolean allStop = true;
        for (PastureBlockData blockData : allChickenList) {
            PastureChickenExtraData extraData = new PastureChickenExtraData();
            if (blockData.getExtraData() != null && blockData.getExtraData() instanceof PastureChickenExtraData) {
                extraData = (PastureChickenExtraData) blockData.getExtraData();
            }
            if (!extraData.isStop()) {
                allStop = false;
                break;
            }
        }
        return allStop;
    }


    /**
     * 灵狐现
     * 传送到当前行以下的空格处
     */
    private void skillOfFox(PastureGameData gameData, int animalId, boolean isRepeat) {
        // 根据优先级获取狐狸,获取后置为空格(从上到下，从左到右)
        List<PastureBlockData> allFoxBlockData = new ArrayList<>();
        for (List<PastureBlockData> dataList : gameData.getBlockDataList()) {
            Iterator<PastureBlockData> blockDataIterator = dataList.iterator();
            while (blockDataIterator.hasNext()) {
                PastureBlockData blockData = blockDataIterator.next();
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                allFoxBlockData.add(blockData);
                blockDataIterator.remove();
            }
        }
        // 获取空格的优先级(从下到上，从左到右)
        for (int y = gameData.getBlockDataList().size() - 1; y >= 0; y--) {
            // 全部传送完毕，结束循环
            if (allFoxBlockData.size() == 0) {
                break;
            }
            // 获取行数据
            List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
            // 获取当前行的空格
            List<Integer> emptyIndex = getEmptyIndex(gameData, y);
            for (Integer index : emptyIndex) {
                if (allFoxBlockData.size() == 0) {
                    break;
                }
                // 获取一只狐狸
                PastureBlockData blockData = allFoxBlockData.remove(0);
                addMoveData(gameData, destroyBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
                // 更改数据
                blockDataChange(blockData, y, index, index);
                dataList.add(blockData);
                addMoveData(gameData, generateBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
            }
        }
    }

    /**
     * 猫伸展
     * 头尾伸展占满两侧空格
     */
    private void skillOfCat(PastureGameData gameData, int animalId, boolean isRepeat) {
        for (int y = 0; y < gameData.getBlockDataList().size(); y++) {
            // 获取当前行的空格
            List<Integer> emptyIndex = getEmptyIndex(gameData, y);
            List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
            for (PastureBlockData blockData : dataList) {
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                int left = blockData.getLeft();
                int right = blockData.getRight();
                // 向左伸展
                while (emptyIndex.contains(left - 1)) {
                    emptyIndex.remove(new Integer(left - 1));
                    left = left - 1;
                }
                // 向右伸展
                while (emptyIndex.contains(right + 1)) {
                    emptyIndex.remove(new Integer(right + 1));
                    right = right + 1;
                }
                // 记录移动过程
                PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
                moveResult.setOriginBlockData(blockData.clone());
                // 更改数据
                blockDataChange(blockData, blockData.getY(), left, right);
                moveResult.setTargetBlockData(blockData.clone());
                moveResult.setMoveType(ePastureGameMoveType.Skill.getValue());
                addMoveData(gameData, moveResult);
            }
        }
    }

    /**
     * 贪吃蛇
     * 头先伸长1格，吞掉相叠动物(n×1)，再伸长n+1格，反复，直到不满足条件
     */
    private void skillOfSnake(PastureGameData gameData, int animalId, boolean isRepeat) {
        List<PastureBlockData> allSnakeBlockData = new ArrayList<>();
        for (int y = 0; y < gameData.getBlockDataList().size(); y++) {
            List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
            for (PastureBlockData blockData : dataList) {
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                allSnakeBlockData.add(blockData);
            }
        }
        // 第一步记录蛇移动的方向
        for (PastureBlockData blockData : allSnakeBlockData) {
            PastureSnakeExtraData extraData = new PastureSnakeExtraData();
            // 获取左侧的非空格数量
            int leftCnt = 0;
            List<Integer> leftNotEmptyBlockList = getNotEmptyIndex(gameData, blockData.getY(), 0, blockData.getLeft() - 1);
            int tempLeft = blockData.getLeft();
            while (leftNotEmptyBlockList.contains(tempLeft - 1)) {
                leftCnt++;
                tempLeft = tempLeft - 1;
            }

            // 获取右侧的非空格数量
            int rightCnt = 0;
            List<Integer> rightNotEmptyBlockList = getNotEmptyIndex(gameData, blockData.getY(), blockData.getRight() + 1, PastureMgr.MAX_WIDTH - 1);
            int tempRight = blockData.getRight();
            while (rightNotEmptyBlockList.contains(tempRight + 1)) {
                rightCnt++;
                tempRight = tempRight + 1;
            }

            // 确定下一步伸长的方向
            int direction;
            // 依次朝着与自身相邻方块较多的一侧(左/右)，伸长1格
            if (leftCnt > rightCnt) {
                direction = -1;
            } else if (leftCnt < rightCnt) {
                direction = 1;
            } else {
                // 若两侧(左/右)相邻方块数相等(≥0)，则向左侧伸长1格
                direction = -1;
            }
            // 若一侧为盘面边缘，则向另一侧伸长1格
            if (blockData.getLeft() == 0) {
                direction = 1;
            } else if (blockData.getRight() == PastureMgr.MAX_WIDTH - 1) {
                direction = -1;
            }
            blockData.setDirection(direction);
            blockData.setExtraData(extraData);
        }
        // 第二步开始移动
        // 记录被吃掉的蛇
        List<PastureBlockData> removeBlockData = new ArrayList<>();
        for (PastureBlockData blockData : allSnakeBlockData) {
            addOneStep(gameData);
            PastureSnakeExtraData extraData = new PastureSnakeExtraData();
            if (blockData.getExtraData() != null && blockData.getExtraData() instanceof PastureSnakeExtraData) {
                extraData = (PastureSnakeExtraData) blockData.getExtraData();
            }
            // 被吃掉了跳过处理
            if (removeBlockData.contains(blockData)) {
                continue;
            }


            PastureBlockData originBlockData = blockData.clone();
            blockData.setUseSkill(true);
            // 防止死循环
            int loopTimes = 0;
            while (!extraData.isStop()) {
                if (loopTimes++ > 1000) {
                    break;
                }
                // 原先的方向
                int originDirection = blockData.getDirection();
                snakeMove(gameData, blockData, extraData, removeBlockData);
                int newDirection = blockData.getDirection();
                if (originDirection != newDirection) {
                    PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
                    moveResult.setOriginBlockData(originBlockData.clone());
                    moveResult.setTargetBlockData(blockData.clone());
                    moveResult.setMoveType(ePastureGameMoveType.Skill.getValue());
                    addMoveData(gameData, moveResult);
                    addOneStep(gameData);
                    originBlockData = blockData.clone();
                }
            }
            blockData.setExtraData(extraData);
            // 记录移动过程
            PastureMoveBlockResult moveResult = new PastureMoveBlockResult();
            moveResult.setOriginBlockData(originBlockData.clone());
            moveResult.setTargetBlockData(blockData.clone());
            moveResult.setMoveType(ePastureGameMoveType.Skill.getValue());
            addMoveData(gameData, moveResult);
            addOneStep(gameData);
        }
    }

    /**
     * 蛇吃动物
     */
    private void snakeMove(PastureGameData gameData, PastureBlockData blockData, PastureSnakeExtraData extraData, List<PastureBlockData> removeBlockData) {
        if (extraData.isStop()) {
            return;
        }
        // 获取蛇移动的方向
        int direction = blockData.getDirection();
        if (direction == -1) {
            // 往左吃
            // 是否重合继续伸长
            boolean isCoincide = false;
            if (extraData.getChangeLen() == 0) {
                // 判断当前位置有没有重合
                List<PastureBlockData> blockDataList = getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY(), blockData);
                if (blockDataList.size() == 0) {
                    // 判断下左边有没有相邻的
                    blockDataList = getBlockDataList(gameData, blockData.getLeft() - 1, blockData.getRight(), blockData.getY(), blockData);
                    if (blockDataList.size() == 0) {
                        extraData.setStop(true);
                        return;
                    }
                }
                isCoincide = true;
            }
            if (!isCoincide) {
                // 先伸长一下
                blockData.setLeft(Math.max(0, blockData.getLeft() - 1));
                // 伸长一次
                extraData.setChangeLen(extraData.getChangeLen() - 1);
                // 更新下长度
                blockData.setLength(blockData.getRight() - blockData.getLeft() + 1);
            }
            // 判断下重叠的动物，吃掉他
            List<PastureBlockData> blockDataList = getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY(), blockData);
            if (blockDataList.size() == 0) {
                // 判断下有没有相邻的
                blockDataList = getBlockDataList(gameData, blockData.getLeft() - 1, blockData.getRight(), blockData.getY(), blockData);
                if (blockDataList.size() == 0) {
                    // 没有动物可以吃了
                    if (extraData.getChangeLen() > 0 && blockData.getLength() < PastureMgr.MAX_WIDTH) {
                        // 掉转方向
                        if (blockData.getLeft() == 0) {
                            blockData.setDirection(-direction);
                        }
                    } else {
                        extraData.setStop(true);
                    }
                    return;
                }
            }
            for (PastureBlockData data : blockDataList) {
                // 吃完的长度为len+tempLen+1
                int resultLen = blockData.getLength() + data.getLength() + 1;
                int resultLeft = blockData.getRight() - resultLen + 1;
                if (resultLeft < 0) {
                    // +1 掉头时需要检测一次
                    extraData.setChangeLen(extraData.getChangeLen() - resultLeft + 1);
                    resultLeft = 0;
                }
                blockData.setLeft(resultLeft);
                blockData.setLength(blockData.getRight() - blockData.getLeft() + 1);
                // 加分
                blockData.setExtraScore(blockData.getExtraScore() + data.getScore());
                // 加能量
                blockData.setExtraEnergy(blockData.getExtraEnergy() + data.getEnergy());
                // 移除动物
                gameData.getBlockDataList().get(data.getY()).remove(data);
                addMoveData(gameData, destroyBlockDataChange(data.clone(), ePastureGameMoveType.Skill.getValue()));
                // 如果蛇被吃掉，则移除吃掉蛇的对象
                removeBlockData.add(data);
            }
        } else {
            // 往右吃
            // 是否重合继续伸长
            boolean isCoincide = false;
            if (extraData.getChangeLen() == 0) {
                // 判断当前位置有没有重合
                List<PastureBlockData> blockDataList = getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY(), blockData);
                if (blockDataList.size() == 0) {
                    // 判断下右边有没有相邻
                    blockDataList = getBlockDataList(gameData, blockData.getLeft(), blockData.getRight() + 1, blockData.getY(), blockData);
                    if (blockDataList.size() == 0) {
                        extraData.setStop(true);
                        return;
                    }
                }
                isCoincide = true;
            }
            if (!isCoincide) {
                // 先伸长一下
                blockData.setRight(Math.min(PastureMgr.MAX_WIDTH - 1, blockData.getRight() + 1));
                // 伸长一次
                extraData.setChangeLen(extraData.getChangeLen() - 1);
                // 更新下长度
                blockData.setLength(blockData.getRight() - blockData.getLeft() + 1);
            }
            // 判断下重叠的动物，吃掉他
            List<PastureBlockData> blockDataList = getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY(), blockData);
            if (blockDataList.size() == 0) {
                // 判断下有没有相邻
                blockDataList = getBlockDataList(gameData, blockData.getLeft(), blockData.getRight() + 1, blockData.getY(), blockData);
                if (blockDataList.size() == 0) {
                    // 没有动物可以吃了
                    if (extraData.getChangeLen() > 0 && blockData.getLength() < PastureMgr.MAX_WIDTH) {
                        // 掉转方向
                        if (blockData.getRight() == PastureMgr.MAX_WIDTH - 1) {
                            blockData.setDirection(-direction);
                        }
                    } else {
                        extraData.setStop(true);
                    }
                    return;
                }
            }
            for (PastureBlockData data : blockDataList) {
                // 吃完的长度为len+tempLen+1
                int resultLen = blockData.getLength() + data.getLength() + 1;
                int resultRight = blockData.getLeft() + resultLen - 1;
                if (resultRight > PastureMgr.MAX_WIDTH - 1) {
                    // +1 掉头时需要检测一次
                    extraData.setChangeLen(extraData.getChangeLen() + resultRight - PastureMgr.MAX_WIDTH + 1 + 1);
                    resultRight = PastureMgr.MAX_WIDTH - 1;
                }
                blockData.setRight(resultRight);
                blockData.setLength(blockData.getRight() - blockData.getLeft() + 1);
                // 加分
                blockData.setExtraScore(blockData.getExtraScore() + data.getScore());
                // 加能量
                blockData.setExtraEnergy(blockData.getExtraEnergy() + data.getEnergy());
                // 移除动物
                gameData.getBlockDataList().get(data.getY()).remove(data);
                addMoveData(gameData, destroyBlockDataChange(data.clone(), ePastureGameMoveType.Skill.getValue()));
                // 如果蛇被吃掉，则移除吃掉蛇的对象
                removeBlockData.add(data);
            }
        }
    }

    /**
     * 胆小鼬
     * 居中蜷缩成1个{len}×1的小鼬
     */
    private void skillOfWeasel(PastureGameData gameData, int animalId, boolean isRepeat) {
        // 获取技能配置
        PastureConfig config = PastureMgr.getConfig();
        PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
        if (animalConfig == null) {
            return;
        }
        int skillId = animalConfig.getSkillId();
        PastureSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return;
        }
        // 需要记录生成的数据
        List<PastureBlockData> needGenerateBlockDataList = new ArrayList<>();
        for (int y = 0; y < gameData.getBlockDataList().size(); y++) {
            List<PastureBlockData> dataList = gameData.getBlockDataList().get(y);
            for (PastureBlockData blockData : dataList) {
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                int left = blockData.getLeft();
                int right = blockData.getRight();
                // 长度
                int len = Integer.parseInt(skillConfig.getSkillParam().split("\\|")[0]) / 1000;
                // 居中蜷缩
                int targetLeft = (left + right + len - 1) / 2;
                int targetRight = targetLeft + len - 1;
                // 原先的消失
                addMoveData(gameData, destroyBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
                blockDataChange(blockData, blockData.getY(), targetLeft, targetRight);
                needGenerateBlockDataList.add(blockData);
            }
        }
        // 生成添加一步
        addOneStep(gameData);
        // 全部消失后生成
        needGenerateBlockDataList.forEach(blockData -> addMoveData(gameData, generateBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue())));
    }

    /**
     * 三只小猪
     * 分裂变成{0}个1×1的小猪
     */
    private void skillOfPig(PastureGameData gameData, int animalId, boolean isRepeat) {
        // 获取技能配置
        PastureConfig config = PastureMgr.getConfig();
        PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
        if (animalConfig == null) {
            return;
        }
        int skillId = animalConfig.getSkillId();
        PastureSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return;
        }
        List<PastureBlockData> allPigBlockData = new ArrayList<>();
        for (List<PastureBlockData> dataList : gameData.getBlockDataList()) {
            Iterator<PastureBlockData> blockDataIterator = dataList.iterator();
            while (blockDataIterator.hasNext()) {
                PastureBlockData blockData = blockDataIterator.next();
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                // 准备裂开
                allPigBlockData.add(blockData);
                addMoveData(gameData, destroyBlockDataChange(blockData.clone(), ePastureGameMoveType.Skill.getValue()));
                blockDataIterator.remove();
            }
        }
        // 裂开添加一步
        addOneStep(gameData);
        // 所有小猪开始裂开
        for (PastureBlockData pigBlockData : allPigBlockData) {
            // 获取猪这行的空格
            List<Integer> emptyIndex = getEmptyIndex(gameData, pigBlockData.getY());
            // 大猪的头的位置
            int left = pigBlockData.getLeft();
            // 计算能裂开成几只
            int cnt = pigBlockData.getLength();
            for (int i = 0; i < cnt; i++) {
                int targetLeft = left + i;
                // 检测下有没有位置放小猪
                if (!emptyIndex.contains(targetLeft)) {
                    continue;
                }
                // 记录一下本体的尺寸吧
                PasturePigExtraData extraData = new PasturePigExtraData();
                extraData.setOriginSize(pigBlockData.getLength());
                // 生成新的小猪
                PastureBlockData newPigBlockData = new PastureBlockData();
                newPigBlockData.setAnimalId(pigBlockData.getAnimalId());
                newPigBlockData.setY(pigBlockData.getY());
                newPigBlockData.setLeft(targetLeft);
                newPigBlockData.setRight(targetLeft);
                newPigBlockData.setLength(1);
                newPigBlockData.setScore(pigBlockData.getScore() / cnt);
                newPigBlockData.setEnergy(pigBlockData.getEnergy() / cnt);
                newPigBlockData.setUseSkill(true);
                newPigBlockData.setExtraData(extraData);
                // 把小猪放进去
                addBlockData(gameData, pigBlockData.getY(), newPigBlockData);
                // 生成新对象
                addMoveData(gameData, generateBlockDataChange(newPigBlockData, ePastureGameMoveType.Skill.getValue()));
            }
        }
    }

    /**
     * 驴
     */
    private void skillOfDonkey(PastureGameData gameData, int animalId, boolean isRepeat) {
        // 从上往下
        List<PastureBlockData> allDonkeyBlockData = new ArrayList<>();
        for (List<PastureBlockData> dataList : gameData.getBlockDataList()) {
            for (PastureBlockData blockData : dataList) {
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                allDonkeyBlockData.add(blockData);
            }
        }
        Set<PastureBlockData> allBlockData = new HashSet<>();
        for (PastureBlockData blockData : allDonkeyBlockData) {
            // 获取驴上下左右的对象
            // 上
            allBlockData.addAll(getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY() - 1, blockData));
            // 下
            allBlockData.addAll(getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY() + 1, blockData));
            // 左右
            allBlockData.addAll(getBlockDataList(gameData, blockData.getLeft() - 1, blockData.getRight() + 1, blockData.getY(), blockData));
        }
        // 改变
        for (PastureBlockData blockData : allBlockData) {
            if (blockData.getLength() <= 1) {
                continue;
            }
            // 计算可缩短长度
            int aroundBlockCnt = getAroundBlockCnt(gameData, blockData, ePastureAnimalType.Donkey.getValue());
            // 最短可缩小到长度1
            aroundBlockCnt = Math.min(aroundBlockCnt + 1, blockData.getLength() - 1);
            // 记录移动过程
            addMoveData(gameData, destroyBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
            // 尾部缩短
            cutTailBlock(blockData, aroundBlockCnt);
            addMoveData(gameData, generateBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
        }
        addOneStep(gameData);
        // 场上所有驴从尾部缩短1格
        for (PastureBlockData blockData : allDonkeyBlockData) {
            if (blockData.getLength() <= 1) {
                continue;
            }
            // 记录移动过程
            addMoveData(gameData, destroyBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
            // 尾部缩短
            cutTailBlock(blockData, 1);
            addMoveData(gameData, generateBlockDataChange(blockData, ePastureGameMoveType.Skill.getValue()));
        }
    }

    /**
     * 获取周围指定动物的数量
     */
    private int getAroundBlockCnt(PastureGameData gameData, PastureBlockData blockData, int animalId) {
        int cnt = 0;
        List<PastureBlockData> allBlockData = new ArrayList<>();
        // 上
        allBlockData.addAll(getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY() - 1, blockData));
        // 下
        allBlockData.addAll(getBlockDataList(gameData, blockData.getLeft(), blockData.getRight(), blockData.getY() + 1, blockData));
        // 左右
        allBlockData.addAll(getBlockDataList(gameData, blockData.getLeft() - 1, blockData.getRight() + 1, blockData.getY(), blockData));
        for (PastureBlockData allBlockDatum : allBlockData) {
            if (allBlockDatum.getAnimalId() == animalId) {
                cnt++;
            }
        }
        return cnt;
    }


    /**
     * 北极熊
     * 每激活1个，冻结盘面{0}个回合，盘面全消后立即解冻
     */
    private void skillOfBear(PastureGameData gameData, int animalId, boolean isRepeat) {
        // 获取技能配置
        PastureConfig config = PastureMgr.getConfig();
        PastureAnimalConfig animalConfig = config.getAnimalConfigMap().get(animalId);
        if (animalConfig == null) {
            return;
        }
        int skillId = animalConfig.getSkillId();
        PastureSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return;
        }
        // 统计有多少熊
        int cnt = 0;
        for (List<PastureBlockData> dataList : gameData.getBlockDataList()) {
            for (PastureBlockData blockData : dataList) {
                if (blockData.getAnimalId() != animalId) {
                    continue;
                }
                // 是否能重复触发
                if (!isRepeat && blockData.isUseSkill()) {
                    continue;
                }
                blockData.setUseSkill(true);
                cnt++;
            }
        }
        // 计算每只冻结几回合
        int round = Integer.parseInt(skillConfig.getSkillParam().split("\\|")[0]) / 1000;
        int limit = Integer.parseInt(skillConfig.getSkillParam().split("\\|")[1]) / 1000;
        // 冻结盘面，每激活n头熊，冻结牧场n+1个回合
        gameData.setFreezeRound(gameData.getFreezeRound() + Math.max(limit, cnt * round));
    }


    // ==========================技能相关=================================

}
